//
// Created by yanhai on 2020/4/29.
//

#include <iostream>
#include <string>
#include <cassert>

using namespace std;

// ================ 案例一 ================
// 类的外部形成类型的访问能力
// 模板名<模板实参>::类型名 变量名;
template<typename T>
struct map {
    typedef T value_type;
    typedef T &reference;
    typedef T *pointer;
};

// 实现：我们内嵌了数据类型==》从模板传入的类型延伸出了其对象相关类型的能力
// 内嵌数据类型表
void test1()
{
    map<int>::value_type a = 100.9; // a is 100
    assert(a == 100);
    map<double>::value_type b = 100.9;
    assert(b == 100.9);
    map<string>::value_type s = "hello";
    assert(s == string("hello"));
}

// ================ 案例二 ================
// 如果一个类模板中，全部的成员都是公有数据类型，那么这个模板就是一个独立的数据类型表
// 用来规范数据的

// 第一步，我们定义一个规范类模板类型表的基类模板
template<typename T, typename U>
class TypeTB1 {
public:
    typedef T value_type1;
    typedef T &reference1;
    typedef U value_type2;
    typedef U &reference2;
};

// 第二步，凡是继承了这个类型表的类模板，它的访问类型就被确定了
template<typename T, typename U>
class A : public TypeTB1<T, U> {

};

void test2()
{
    A<int, double>::value_type1 a = 200;
    A<int, double>::reference1 b = a;
    assert(a == 200);
    assert(b == 200);
}

// 在STL库中，设计人员经常使用这种技巧
// binary,对二元函数的形参类型进行了约束
template<typename _A1, typename _A2, typename _R>
struct binary {
    typedef _A1 Arg1;
    typedef _A2 Arg2;
    typedef _R Rtn;
};

// 设计一个类继承上面的binary
template<typename T1, typename T2, typename TR>
class Add : public binary<T1, T2, TR> {
public:
    TR bFunction(const T1 &x, const T2 &y) const
    {
        return x + y;
    }
};

void test3()
{
    double a = 100.01, b = 20.2;
    Add<double, double, double> addObj;
    double c = addObj.bFunction(a, b);
    cout << c << endl;

    // 使用Arg1定义一个变量x
    Add<int, int, double>::Arg1 x = 100;

    // 因为Add包含了binary的数据类型表，因此，系统中的其他模块就可以使用
    // Add::Arg1  Add::Arg2  Add::Rtn这种方式和Add本身进行对接。
    // 这种数据类型的抽象：达到了多个系统模块之间的类型统一。
}

int main()
{
    test1();
    test2();
    test3();
    return 0;
}
